#include "audio_encoder.h"

my_encoder_t my_encoder;

esp_audio_enc_handle_t encoder = NULL;
void                   audio_encoder_init(void)
{
    // opus编码器配置
    esp_opus_enc_config_t opus_cfg = {
        .sample_rate      = 16000,                               // 采样率
        .channel          = 1,                                   // 单通道
        .bits_per_sample  = 16,                                  // 采样位数
        .bitrate          = 32000,                               // 码率
        .frame_duration   = ESP_OPUS_ENC_FRAME_DURATION_60_MS,   // 帧时长
        .application_mode = ESP_OPUS_ENC_APPLICATION_AUDIO,      // 应用模式: 音频
        .complexity       = 5,                                   // 复杂度: 0-10
        .enable_fec       = false,
        .enable_dtx       = false,
        .enable_vbr       = false};

    // 打开编码器
    esp_opus_enc_open(&opus_cfg, sizeof(esp_opus_enc_config_t), &encoder);
}

void audio_encoder_task(void *);
void audio_encoder_start(RingbufHandle_t input, RingbufHandle_t output)
{
    my_encoder.input  = input;
    my_encoder.output = output;

    my_encoder.is_running = true;

    xTaskCreatePinnedToCoreWithCaps(audio_encoder_task,
                                    "audio_encoder_task",
                                    64 * 1024,
                                    NULL,
                                    5,
                                    NULL,
                                    1,   // cpu核心
                                    MALLOC_CAP_SPIRAM);
}

/**
 * @brief 从环形把缓冲区copy  size个数据到 data
 *
 * @param ringBuf
 * @param data
 * @param size
 */
void copy_from_ringbuf(RingbufHandle_t ringBuf,
                       uint8_t        *to_buffer,
                       int             size)
{
    while(size > 0)
    {
        size_t real_len = 0;
        void  *data     = xRingbufferReceiveUpTo(ringBuf, &real_len, portMAX_DELAY, size);
        memcpy(to_buffer, data, real_len);
        vRingbufferReturnItem(ringBuf, data);   // 归还缓冲区
        size -= real_len;                       // 更新剩余待读取的数据的长度
        to_buffer += real_len;                  // 移动指针
    }
}
void audio_encoder_task(void *args)
{
    // 分配存储输入和输出音频的内存空间
    int in_size = 0, out_size = 0;
    esp_opus_enc_get_frame_size(encoder, &in_size, &out_size);
    uint8_t *in_data  = heap_caps_malloc(in_size, MALLOC_CAP_SPIRAM);
    uint8_t *out_data = heap_caps_malloc(out_size, MALLOC_CAP_SPIRAM);

    // 输入音频帧
    esp_audio_enc_in_frame_t in_frame = {
        .buffer = in_data,
        .len    = in_size,
    };
    // 输出音频帧
    esp_audio_enc_out_frame_t out_frame = {
        .buffer = out_data,
        .len    = out_size,
    };
    while(my_encoder.is_running)
    {

        copy_from_ringbuf(my_encoder.input, in_frame.buffer, in_frame.len);
        // 进行编码
        esp_opus_enc_process(encoder, &in_frame, &out_frame);

        // 把编码后的数据放入到输出环形缓冲区
        xRingbufferSend(my_encoder.output, out_frame.buffer, out_frame.encoded_bytes, 0);
    }

    free(in_data);
    free(out_data);

    vTaskDelete(NULL);
}
